package com.zhiche.wms.service.stock.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.zhiche.wms.core.supports.BaseException;
import com.zhiche.wms.core.supports.enums.InterfaceVisitTypeEnum;
import com.zhiche.wms.core.supports.enums.TableStatusEnum;
import com.zhiche.wms.core.utils.SnowFlakeId;
import com.zhiche.wms.domain.mapper.base.StorehouseMapper;
import com.zhiche.wms.domain.mapper.certification.CertificationInfoMapper;
import com.zhiche.wms.domain.mapper.inbound.FactoryPrepareInboundMapper;
import com.zhiche.wms.domain.mapper.log.CancelStoreLogMapper;
import com.zhiche.wms.domain.mapper.otm.OtmOrderReleaseMapper;
import com.zhiche.wms.domain.mapper.stock.SkuMapper;
import com.zhiche.wms.domain.mapper.stock.StockDetailMapper;
import com.zhiche.wms.domain.mapper.stock.StockMapper;
import com.zhiche.wms.domain.mapper.stockadjust.StockAdjustHeaderMapper;
import com.zhiche.wms.domain.mapper.stockadjust.StockAdjustLineMapper;
import com.zhiche.wms.domain.model.base.StoreLocation;
import com.zhiche.wms.domain.model.base.Storehouse;
import com.zhiche.wms.domain.model.certification.CertificationInfo;
import com.zhiche.wms.domain.model.inbound.FactoryPrepareInbound;
import com.zhiche.wms.domain.model.inbound.InboundPutawayLine;
import com.zhiche.wms.domain.model.log.CancelStoreLog;
import com.zhiche.wms.domain.model.movement.MovementHeader;
import com.zhiche.wms.domain.model.movement.MovementLine;
import com.zhiche.wms.domain.model.otm.OtmOrderRelease;
import com.zhiche.wms.domain.model.outbound.OutboundNoticeLine;
import com.zhiche.wms.domain.model.stock.Sku;
import com.zhiche.wms.domain.model.stock.Stock;
import com.zhiche.wms.domain.model.stock.StockDetail;
import com.zhiche.wms.domain.model.stock.StockProperty;
import com.zhiche.wms.domain.model.stockadjust.StockAdjustHeader;
import com.zhiche.wms.domain.model.stockadjust.StockAdjustLine;
import com.zhiche.wms.domain.model.stockinit.StockInitLine;
import com.zhiche.wms.domain.model.sys.User;
import com.zhiche.wms.domain.model.sys.UserStorehouse;
import com.zhiche.wms.dto.outbound.StockSkuToPrepareDTO;
import com.zhiche.wms.dto.outbound.StockSkuToPrepareParamDTO;
import com.zhiche.wms.dto.stock.FactoryPrepareStockDTO;
import com.zhiche.wms.dto.stock.StockDTO;
import com.zhiche.wms.dto.stock.StockQty;
import com.zhiche.wms.dto.stock.StockWithSkuDTO;
import com.zhiche.wms.service.base.IBusinessDocNumberService;
import com.zhiche.wms.service.base.IStoreLocationService;
import com.zhiche.wms.service.inbound.IInboundPutawayLineService;
import com.zhiche.wms.service.movement.IMovementHeaderService;
import com.zhiche.wms.service.opbaas.IOrderReleaseService;
import com.zhiche.wms.service.stock.IStockService;
import com.zhiche.wms.service.stockinit.IStockInitLineService;
import com.zhiche.wms.service.sys.IUserService;
import com.zhiche.wms.service.sys.IUserStorehouseService;
import com.zhiche.wms.service.utils.CommonFields;
import com.zhiche.wms.service.utils.CommonMethod;
import com.zhiche.wms.service.utils.CommonValueConstant;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 库存 服务实现类
 * </p>
 *
 * @author zhaoguixin
 * @since 2018-05-30
 */
@Service
public class StockServiceImpl extends ServiceImpl<StockMapper, Stock> implements IStockService {
    private static final Logger LOGGER = LoggerFactory.getLogger(StockServiceImpl.class);

    @Autowired
    private SkuServiceImpl skuService;
    @Autowired
    private SnowFlakeId snowFlakeId;
    @Autowired
    private StockDetailServiceImpl stockDetailService;
    @Autowired
    private IBusinessDocNumberService numberService;
    @Autowired
    private IUserService userService;
    @Autowired
    private IMovementHeaderService movementHeaderService;
    @Autowired
    private IOrderReleaseService orderReleaseService;
    @Autowired
    private IInboundPutawayLineService putawayLineService;
    @Autowired
    private IStockInitLineService initLineService;
    @Autowired
    private CancelStoreLogMapper cancelStoreLogMapper;
    @Autowired
    private OtmOrderReleaseMapper otmOrderReleaseMapper;
    @Autowired
    private StorehouseMapper storehouseMapper;
    @Autowired
    private StockDetailMapper stockDetailMapper;
    @Autowired
    private IUserStorehouseService iUserStorehouseService;
    @Autowired
    private CertificationInfoMapper certificationInfoMapper;
    @Autowired
    private StockAdjustHeaderMapper stockAdjustHeaderMapper;
    @Autowired
    private StockAdjustLineMapper stockAdjustLineMapper;
    @Autowired
    private SkuMapper skuMapper;
    @Autowired
    private IStoreLocationService storeLocationService;
    @Autowired
    private FactoryPrepareInboundMapper factoryMapper;
    @Autowired
    private StockMapper stockMapper;

    @Override
    public Stock getUniqueStock (StockProperty stockProperty) {
        Long skuId = skuService.getUniqueSku(stockProperty).getId();
        LOGGER.info("库存量单位skuId为 {}", skuId);

        EntityWrapper<Stock> ew = new EntityWrapper<>();
        ew.eq("store_house_id", stockProperty.getStoreHouseId());
        ew.eq("location_id", stockProperty.getLocationId());
        ew.eq("sku_id", skuId);
        Stock stock = selectOne(ew);
        LOGGER.info("查询库存量信息(为空就会新增)为 stock ： {}", stock);
        if (Objects.equals(null, stock)) {
            stock = new Stock();
            stock.setStoreHouseId(stockProperty.getStoreHouseId());
            stock.setLocationId(stockProperty.getLocationId());
            stock.setSkuId(skuId);
            stock.setId(snowFlakeId.nextId());
            stock.setQty(BigDecimal.ZERO);
            stock.setNetWeight(BigDecimal.ZERO);
            stock.setGrossWeight(BigDecimal.ZERO);
            stock.setGrossCubage(BigDecimal.ZERO);
            stock.setPackedCount(BigDecimal.ZERO);

            boolean result = insert(stock);
            if (result) {
                return stock;
            } else {
                throw new BaseException(2000, "保存库存失败");
            }
        } else {
            return stock;
        }
    }

    @Override
//    @Transactional
    public Stock addStock (StockProperty stockProperty, String businessType, Long relationLineId) {
        return updateStockQty(stockProperty, "10", businessType, relationLineId);
    }

    @Override
    @Transactional
    public Stock minusStock (StockProperty stockProperty, String businessType, Long relationLineId) {
        if (Objects.equals(null, stockProperty.getQty())) throw new BaseException(2040, "数量不能为空！");
        stockProperty.setQty(BigDecimal.ZERO.subtract(stockProperty.getQty()));

        if (!Objects.equals(null, stockProperty.getNetWeight()))
            stockProperty.setNetWeight(BigDecimal.ZERO.subtract(stockProperty.getNetWeight()));
        if (!Objects.equals(null, stockProperty.getGrossWeight()))
            stockProperty.setGrossWeight(BigDecimal.ZERO.subtract(stockProperty.getGrossWeight()));
        if (!Objects.equals(null, stockProperty.getGrossCubage()))
            stockProperty.setGrossCubage(BigDecimal.ZERO.subtract(stockProperty.getGrossCubage()));
        if (!Objects.equals(null, stockProperty.getPackedCount()))
            stockProperty.setPackedCount(BigDecimal.ZERO.subtract(stockProperty.getPackedCount()));
        return updateStockQty(stockProperty, "20", businessType, relationLineId);
    }

    @Override
    public List<Stock> queryStockList (StockProperty stockProperty) {
        return baseMapper.queryStockList(stockProperty);
    }

    @Override
    public Page<StockDTO> queryPageStock (Page<StockDTO> page) {
        Wrapper<StockDTO> ew = buildCondition(page.getCondition());
        List<StockDTO> stockDTOList = baseMapper.selectPageStockDTO(page, ew);
        page.setRecords(stockDTOList);
        return page;
    }

    @Override
    public Page<StockDTO> queryPageStockByQrCode (Page<StockDTO> page) {
        if (!page.getCondition().containsKey("key") || Objects.isNull(page.getCondition().get("key"))) {
            throw new BaseException(2000, "扫描内容为空！");
        }
        String vin = getVinFromOR(page.getCondition().get("key").toString());
        page.getCondition().put("lotNo1", vin);
        Wrapper<StockDTO> ew = buildCondition(page.getCondition());
        List<StockDTO> stockDTOList = baseMapper.selectPageStockDTOByQrCode(page, ew);
        page.setRecords(stockDTOList);
        return page;
    }

    private String getVinFromOR (String key) {
        Wrapper<OtmOrderRelease> orEw = new EntityWrapper<>();
        orEw.eq("qr_code", key)
                .ne("status", TableStatusEnum.STATUS_50.getCode())
                .orderBy("id", false);
        List<OtmOrderRelease> orderReleases = orderReleaseService.selectList(orEw);
        if (Objects.nonNull(orderReleases) && orderReleases.size() > 0) {
            return orderReleases.get(0).getVin();
        } else {
            return key;
        }
    }

    @Override
    public List<StockDTO> exportStockData (Map<String, String> condition) {
        if (condition == null || condition.isEmpty()) {
            throw new BaseException("参数不能为空");
        }
        EntityWrapper<StockDTO> ew = new EntityWrapper<>();
        if (StringUtils.isBlank(condition.get("storeHouseId"))) {
            throw new BaseException("仓库信息不能为空");
        }
        ew.eq("store_house_id", condition.get("storeHouseId"));

        if (StringUtils.isNotBlank(condition.get("stockId"))) {
            ew.eq("stock_id", condition.get("stockId"));
        }
        if (StringUtils.isNotBlank(condition.get("lotNo1"))) {
            ew.like("lot_no1", condition.get("lotNo1"));
        }
        if (StringUtils.isNotBlank(condition.get("stockStatus"))) {
            ew.eq("stock_status", condition.get("stockStatus"));
        }
        if (StringUtils.isNotBlank(condition.get("ownerId"))) {
            ew.eq("owner_id", condition.get("ownerId"));
        }
        if (StringUtils.isNotBlank(condition.get("materielId"))) {
            ew.eq("materiel_id", condition.get("materielId"));
        }
        if (StringUtils.isNotBlank(condition.get("locationCode"))) {
            ew.eq("location_code", condition.get("locationCode"));
        }
        ew.groupBy("stock_id");
        ew.orderBy("stock_id", false);
        return baseMapper.selectExportStockData(ew);
    }

    @Override
    public Page<CancelStoreLog> queryCancelStoreLog (Page<CancelStoreLog> page) {
        Map<String, Object> condition = page.getCondition();
        Wrapper<CancelStoreLog> ew = new EntityWrapper<>();
        ew.orderBy("gmt_create", false);
        if (Objects.nonNull(condition)) {
            if (Objects.nonNull(condition.get("storeHouseId")) && StringUtils.isNotEmpty((String) condition.get("storeHouseId"))) {
                ew.eq("store_house_id", condition.get("storeHouseId"));
            }

            if (Objects.nonNull(condition.get("key")) && StringUtils.isNotEmpty((String) condition.get("key"))) {
                ew.andNew().like("vin", (String) condition.get("key")).or().like("owner_order_no", (String) condition.get("key"));
            }
        }
        List<CancelStoreLog> list = cancelStoreLogMapper.queryCancelStoreLog(page, ew);
        return page.setRecords(list);
    }

    @Override
    public void driverReceiveTask (Map<String, String> condition) {
        User loginUser = userService.getLoginUser();
        if (Objects.isNull(loginUser)) {
            throw new BaseException("请登陆后进行该操作");
        }
        String cancelStoreId = condition.get("keyId");
        if (StringUtils.isEmpty(cancelStoreId)) {
            throw new BaseException("退库id为空");
        }
        CancelStoreLog cancelStoreLog = new CancelStoreLog();
        cancelStoreLog.setStatusReceive(CommonValueConstant.RECEIVE_STATUS_20);
        cancelStoreLog.setUserReceive(loginUser.getName());
        Wrapper<CancelStoreLog> ew = new EntityWrapper<>();
        ew.eq("id", cancelStoreId);
        ew.eq("status_receive", CommonValueConstant.RECEIVE_STATUS_10);
        cancelStoreLogMapper.update(cancelStoreLog, ew);
    }

    @Override
    public CancelStoreLog queryCancelStoreDetail (Long houseId, String key, String visitType) {
        CancelStoreLog result = null;
        Wrapper<CancelStoreLog> cslEw = new EntityWrapper<>();
        if (InterfaceVisitTypeEnum.CLICK_TYPE.getCode().equals(visitType)) {
            if (Objects.isNull(key) && StringUtils.isEmpty(key)) {
                throw new BaseException("主键id为空，请重新确认");
            }
            cslEw.eq("id", key);
            result = cancelStoreLogMapper.queryCancelStoreDetail(cslEw);
        } else if (InterfaceVisitTypeEnum.SCAN_TYPE.getCode().equals(visitType)) {
            if (Objects.isNull(key) && StringUtils.isEmpty(key)) {
                throw new BaseException("扫码编码为空，请重新确认");
            }
            if (Objects.isNull(houseId) && StringUtils.isEmpty(String.valueOf(houseId))) {
                throw new BaseException("仓库id【storeHouseId】为空，请重新确认");
            }
            String vin = null;
            Wrapper<OtmOrderRelease> otmEw = new EntityWrapper<>();
            otmEw.eq("qr_code", key);
            otmEw.orderBy("gmt_modified", false);
            List<OtmOrderRelease> otmOrderReleases = otmOrderReleaseMapper.selectList(otmEw);
            if (!CollectionUtils.isEmpty(otmOrderReleases)) {
                vin = otmOrderReleases.get(0).getVin();
            }
            if (StringUtils.isEmpty(vin)) {
                vin = key;
            }
            cslEw.eq("vin", vin);
            result = cancelStoreLogMapper.queryCancelStoreDetail(cslEw);
        } else {
            throw new BaseException("参数不合法");
        }
        return result;
    }

    @Override
    public List<StockSkuToPrepareDTO> selectStockToKeyPrepareByParams (OutboundNoticeLine v, Long storeHouseId) {
        StockSkuToPrepareParamDTO paramDTO = new StockSkuToPrepareParamDTO();
        BeanUtils.copyProperties(v, paramDTO);
        paramDTO.setStoreHouseId(storeHouseId);
        return this.baseMapper.selectStockToPrepareByParams(paramDTO);
    }

    @Override
    public List<Map<String, String>> queryActualStock (Map<String, String> condition) {
        List<Map<String, String>> result = new ArrayList<>();
        String storeHouseCode = condition.get("storeHouseCode");
        if (StringUtils.isEmpty(storeHouseCode)) {
            throw new BaseException("仓库【storeHouseId】不能为空，请重新确认!");
        }
        Wrapper<Storehouse> ew = new EntityWrapper<>();
        ew.in("wsh.code", storeHouseCode.split(","));
        ew.groupBy("wsh.code");
        List<Storehouse> list = storehouseMapper.queryActualStock(ew);
        if (CollectionUtils.isEmpty(list)) {
            throw new BaseException("仓库【storeHouseCode】查询结果为空!");
        }
        for (Storehouse storehouse : list) {
            if (null == storehouse) {
                throw new BaseException("仓库【storeHouseCode】" + storeHouseCode + "查询结果为空!");
            }
            Map<String, String> map = new HashMap<>();
            map.put("storeHouseCode", storehouse.getCode());
            map.put("actualStock", String.valueOf(storehouse.getActualStock()));
            result.add(map);
        }
        return result;
    }

    @Override
    public void cleanStock (Map<String, String> param) {
        if (null == param || param.isEmpty()) {
            throw new BaseException("清理库存必要参数不能为空");
        }
        if (StringUtils.isEmpty(param.get("stockId"))) {
            throw new BaseException("清理库存必要参数不能为空");
        }
        User loginUser = userService.getLoginUser();
        if (Objects.isNull(loginUser)) {
            throw new BaseException("请登陆后进行该操作");
        }
        //清理库存量
        List<Long> stockIds = cleanStockData(param, loginUser.getName());

        //清理库存明细
        cleanStockDetail(stockIds, loginUser.getName());

    }

    @Override
    public Page<StockQty> queryStockQty (Page<StockQty> page) {
        //查询用户关联的所有仓库
        List<Long> storeList = queryUserStoreHouse();
        EntityWrapper<StockQty> stockQtyEw = new EntityWrapper<>();
        stockQtyEw.in("store_house_id", storeList);
        Map<String, Object> condition = page.getCondition();
        if (null != condition && !condition.isEmpty()) {
            if (StringUtils.isNotEmpty((String) condition.get("storeHouseName"))) {
                stockQtyEw.like("name", condition.get("storeHouseName").toString());
            }

            if (StringUtils.isNotEmpty((String) condition.get("lotNo1"))) {
                List<String> vins = Arrays.asList(CommonMethod.setVins((String) condition.get("lotNo1")));
                stockQtyEw.andNew().in("lot_no1", vins).or().like("lot_no1", condition.get("lotNo1").toString());
            }
        }

        List<StockQty> stockQties = baseMapper.queryStockQty(page, stockQtyEw);
        return page.setRecords(stockQties);
    }

    @Override
    public List<StockQty> queryStockQtyDetail (Map<String, Object> param) {
        //入参判断
        EntityWrapper<StockQty> ew = judgeStockParam(param);
        List<StockQty> stockQties = baseMapper.queryStockQtyDetail(ew);
        return stockQties;
    }

    @Override
    public void cleanStockData (Long stockId, String message) {
        Stock stock = new Stock();
        stock.setQty(BigDecimal.ZERO);
        stock.setId(stockId);
        if (StringUtils.isNotBlank(message)) {
            stock.setStockProperty(message);
        }
        baseMapper.updateById(stock);

        StockDetail stockDetail = new StockDetail();
        stockDetail.setQty(BigDecimal.ZERO);
        EntityWrapper<StockDetail> ew = new EntityWrapper<>();
        ew.eq("stock_id", stockId);
        stockDetailMapper.update(stockDetail, ew);
    }

    @Override
    public Page<FactoryPrepareStockDTO> queryFactoryStock (Page<FactoryPrepareStockDTO> page) {
        Map<String, Object> condition = page.getCondition();
        EntityWrapper<FactoryPrepareStockDTO> fpEw = new EntityWrapper<>();
        if (null != condition) {
            if (condition.containsKey(CommonFields.STARTDATE.getCode()) && StringUtils.isNotBlank((String) condition.get(CommonFields.STARTDATE.getCode()))) {
                fpEw.ge("gmtCreated", condition.get(CommonFields.STARTDATE.getCode()));
            }
            if (condition.containsKey(CommonFields.ENDDATE.getCode()) && StringUtils.isNotBlank((String) condition.get(CommonFields.ENDDATE.getCode()))) {
                fpEw.le("gmtCreated", condition.get(CommonFields.ENDDATE.getCode()));
            }
            if (condition.containsKey("shipmentGid") && StringUtils.isNotBlank((String) condition.get("shipmentGid"))) {
                fpEw.like("shipmentGid", (String) condition.get("shipmentGid")).or().eq("shipmentGid", condition.get("shipmentGid"));
            }
            if (condition.containsKey("stockProperty") && StringUtils.isNotBlank((String) condition.get("stockProperty"))) {
                if (TableStatusEnum.STATUS_Y.getCode().equals(condition.get("stockProperty"))) {
                    fpEw.eq("stockProperty", "备转正");
                } else {
                    fpEw.eq("stockProperty", "无单");
                }
            }
            if (condition.containsKey("isShipment") && StringUtils.isNotBlank((String) condition.get("isShipment"))) {
                if (TableStatusEnum.STATUS_Y.getCode().equals(condition.get("isShipment"))) {
                    fpEw.isNotNull("shipmentGid");
                } else {
                    fpEw.isNull("shipmentGid");
                }
            }
            if (condition.containsKey("vin") && StringUtils.isNotBlank((String) condition.get(CommonFields.VIN.getCode()))) {
                List<String> vins = Arrays.asList(CommonMethod.setVins((String) condition.get("vin")));
                fpEw.andNew().in("vin", vins).or().like("vin", condition.get("vin").toString());
            }
        }
        fpEw.orderBy("gmtCreated", false);
        List<FactoryPrepareStockDTO> factoryPrepareStockDTOS;
        if (StringUtils.isNotBlank((String) condition.get("queryType")) && TableStatusEnum.STATUS_Y.getCode().equals(condition.get("queryType"))) {
            factoryPrepareStockDTOS = baseMapper.queryFactoryStock(fpEw, page);
        } else {
            factoryPrepareStockDTOS = baseMapper.queryFactoryStock(fpEw);
        }
        return page.setRecords(factoryPrepareStockDTOS);
    }

    @Override
    public void updateFactoryStockLocation (Map<String, String> condition) {
        User loginUser = userService.getLoginUser();
        if (Objects.isNull(loginUser)) {
            throw new BaseException("请登陆后进行该操作");
        }
        checkUpdateLocationParam(condition);
        String houseId = condition.get("houseId");
        String newAreaId = condition.get("newAreaId");
        String[] factoryIds = condition.get("factoryId").split(",");
        StoreLocation storeLocation = null;
        for (String factoryInboundId : factoryIds) {
            //查询无单信息
            FactoryPrepareInbound queryParam = new FactoryPrepareInbound();
            queryParam.setId(Long.valueOf(factoryInboundId));
            FactoryPrepareInbound factoryResult = factoryMapper.selectOne(queryParam);
            //查询无单区的有效库位
            storeLocation = storeLocationService.queryUsableLocationByAreaId(Long.valueOf(houseId), Long.valueOf(newAreaId));
            if (Objects.isNull(storeLocation)) {
                throw new BaseException("无可用库位！");
            }
            HashMap<String, Object> params = Maps.newHashMap();
            params.put("stockId", factoryResult.getStockId());
            params.put("houseId", houseId);
            List<StockWithSkuDTO> list = selectStockWithSkuByParam(params);
            if (CollectionUtils.isEmpty(list)) {
                throw new BaseException("未查询到对应stockId:" + factoryResult.getStockId() + "的库存信息");
            }
            if (list.size() > 1) {
                throw new BaseException("查询到stockId:" + factoryResult.getStockId() + "的多条库存");
            }
            //无单区有指令已入库的处理方式
            StockWithSkuDTO stockDTO = list.get(0);
            //调整入库记录库位信息
            EntityWrapper<InboundPutawayLine> ew = new EntityWrapper<>();
            ew.eq("lot_no1", stockDTO.getLotNo1());
            ew.eq("materiel_id", stockDTO.getMaterielId());
            ew.eq("owner_id", stockDTO.getOwnerId());
            ew.orderBy("gmt_create", false);
            ew.orderBy("id", false);
            List<InboundPutawayLine> lineList = putawayLineService.selectList(ew);
            Long putwayLineId = null;
            if (CollectionUtils.isNotEmpty(lineList)) {
                HashMap<String, String> propCache = Maps.newHashMap();
                propCache.put("materielName", lineList.get(0).getMaterielName());
                propCache.put("relationId", String.valueOf(lineList.get(0).getId()));
                MovementHeader mh = buildMovement(loginUser, houseId, String.valueOf(storeLocation.getId()), stockDTO, propCache);
                boolean isUpdate = movementHeaderService.createAndAuditMovenment(mh);
                if (!isUpdate) {
                    throw new BaseException("库位调整失败");
                }
                if (null != lineList.get(0).getId()) {
                    InboundPutawayLine inboundPutawayLine = new InboundPutawayLine();
                    inboundPutawayLine.setId(putwayLineId);
                    inboundPutawayLine.setUpdateLocationId(Long.valueOf(storeLocation.getId()));
                    inboundPutawayLine.setUpdateLocationNo(storeLocationService.selectById(storeLocation.getId()).getName());
                    putawayLineService.updateById(inboundPutawayLine);
                }
                updateFactoryLocation(factoryResult.getId(),newAreaId,storeLocation.getId(),storeLocation.getCode());
            } else {
                //无单无指令，未入库调整库位
                updateFactoryLocation(factoryResult.getId(),newAreaId,storeLocation.getId(),storeLocation.getCode());
                Stock stock = new Stock();
                stock.setId(factoryResult.getStockId());
                stock.setLocationId(storeLocation.getId());
                stockMapper.updateById(stock);
            }
        }
    }

    private void updateFactoryLocation (Long factoryId, String newAreaId, Long locationId, String locationCode) {
        FactoryPrepareInbound factoryPrepareInbound = new FactoryPrepareInbound();
        factoryPrepareInbound.setId(factoryId);
        factoryPrepareInbound.setAreaId(Long.valueOf(newAreaId));
        factoryPrepareInbound.setLocationId(locationId);
        factoryPrepareInbound.setLocationNo(locationCode);
        factoryMapper.updateById(factoryPrepareInbound);
    }

    private void checkUpdateLocationParam (Map<String, String> condition) {
        if (Objects.isNull(condition) || condition.isEmpty()) {
            throw new BaseException("参数不能为空");
        }
       /* if (StringUtils.isBlank(condition.get("stockId"))) {
            throw new BaseException("请选择要调整库位的数据");
        }*/
        if (StringUtils.isBlank(condition.get("houseId"))) {
            throw new BaseException("仓库信息不能为空");
        }
        if (StringUtils.isBlank(condition.get("newAreaId"))) {
            throw new BaseException("库区信息不能为空");
        }
        if (StringUtils.isBlank(condition.get("factoryId"))) {
            throw new BaseException("无单信息不能为空");
        }
    }

    /**
     * 库存明细查询入参
     */
    private EntityWrapper<StockQty> judgeStockParam (Map<String, Object> param) {
        if (null == param && param.isEmpty()) {
            throw new BaseException("入参不能为空！");
        }
        if (StringUtils.isEmpty((String) param.get("skuId"))) {
            throw new BaseException("入参【skuId】不能为空！");
        }
        if (StringUtils.isEmpty((String) param.get("lotNo1"))) {
            throw new BaseException("入参【lotNo1】不能为空！");
        }
        if (StringUtils.isEmpty((String) param.get("storeHouseId"))) {
            throw new BaseException("入参【storeHouseId】不能为空！");
        }
        EntityWrapper<StockQty> stockQtyEw = new EntityWrapper<>();
        stockQtyEw.eq("ws.sku_id", param.get("skuId"));
        stockQtyEw.eq("wk.lot_no1", param.get("lotNo1"));
        stockQtyEw.eq("wsh.id", param.get("storeHouseId"));
        return stockQtyEw;
    }

    /**
     * 查询用户所关联仓库
     */
    private List<Long> queryUserStoreHouse () {
        List<Long> storeHouseList = new ArrayList<>();
        List<UserStorehouse> userStorehouses = iUserStorehouseService.getUserHouses();
        for (UserStorehouse storeHouse : userStorehouses) {
            storeHouseList.add(storeHouse.getStoreHouseId());
        }
        return storeHouseList;
    }

    /**
     * 清理库存明细
     *
     * @param stockIds  库存id
     * @param loginName 登录用户
     */
    private void cleanStockDetail (List<Long> stockIds, String loginName) {
        EntityWrapper<StockDetail> sdEw = new EntityWrapper<>();
        sdEw.in("stock_id", stockIds);
        sdEw.eq("type", TableStatusEnum.STATUS_10.getCode());
        sdEw.gt("qty", 0);
        sdEw.groupBy("stock_id");
        List<StockDetail> stockDetails = stockDetailMapper.selectList(sdEw);
        if (CollectionUtils.isNotEmpty(stockDetails)) {
            for (StockDetail stockDetail : stockDetails) {
                EntityWrapper<StockDetail> stockDetailEw = new EntityWrapper<>();
                stockDetailEw.eq("id", stockDetail.getId());
                stockDetailEw.eq("type", TableStatusEnum.STATUS_10.getCode());
                StockDetail updateStockDetail = new StockDetail();
                updateStockDetail.setQty(BigDecimal.ZERO);
                stockDetailMapper.update(updateStockDetail, stockDetailEw);
                //记录库存调整日志
                saveStockLogLine(stockDetail, loginName);
            }
        }
    }

    /**
     * 记录操作日志
     *
     * @param stockDetail 库存明细
     * @param loginName   登录用户
     */
    private void saveStockLogLine (StockDetail stockDetail, String loginName) {
        try {
            Stock stock = baseMapper.selectById(stockDetail.getStockId());
            StockAdjustHeader stockAdjustHeader = new StockAdjustHeader();
            stockAdjustHeader.setUserCreate(loginName);
            stockAdjustHeader.setId(snowFlakeId.nextId());
            stockAdjustHeader.setStoreHouseId(stock.getStoreHouseId());
            stockAdjustHeader.setAdjustNo(String.valueOf(stock.getId()));
            stockAdjustHeaderMapper.insert(stockAdjustHeader);

            StockAdjustLine stockAdjustLine = new StockAdjustLine();
            stockAdjustLine.setHeaderId(stockAdjustHeader.getId());
            Sku sku = skuMapper.selectById(stock.getSkuId());
            if (null != sku) {
                stockAdjustLine.setLotNo1(sku.getLotNo1());
            }
            stockAdjustLine.setOwnerId(String.valueOf(stockDetail.getId()));
            stockAdjustLineMapper.insert(stockAdjustLine);
        } catch (Exception e) {
            LOGGER.error("清理库存存储投标日志异常", e.getMessage());
        }
    }

    /**
     * 清理库存
     */
    private List<Long> cleanStockData (Map<String, String> param, String loginName) {
        EntityWrapper<Stock> stockEw = new EntityWrapper<>();
        String[] ids = param.get("stockId").split(",");
        stockEw.in("id", Arrays.asList(ids));
        stockEw.gt("qty", TableStatusEnum.STATUS_0.getCode());
        List<Stock> stocks = baseMapper.selectList(stockEw);
        if (ids.length != stocks.size()) {
            throw new BaseException("有未查询到的数据，请单独取消！");
        }
        //清理库存明细
        List<Long> stockIds = new ArrayList<>();
        for (Stock stock : stocks) {
            //清理库存
            if (stock.getQty().compareTo(BigDecimal.ZERO) > 0) {
                Stock updateStock = new Stock();
                updateStock.setQty(stock.getQty().subtract(new BigDecimal(1)));
                updateStock.setId(stock.getId());
                baseMapper.updateById(updateStock);
            }
            stockIds.add(stock.getId());
        }
        return stockIds;
    }

    private Wrapper<StockDTO> buildCondition (Map<String, Object> condition) {
        Wrapper<StockDTO> ew = new EntityWrapper<>();
        if (!Objects.isNull(condition) && !condition.isEmpty()) {
            if (condition.containsKey("stockId") && Objects.nonNull(condition.get("stockId"))) {
                ew.eq("stock_id", condition.get("stockId").toString());
            }
            if (condition.containsKey("stockStatus") && Objects.nonNull(condition.get("stockStatus"))) {
                ew.eq("stock_status", condition.get("stockStatus").toString());
            }
            if (condition.containsKey("ownerId") && Objects.nonNull(condition.get("ownerId"))) {
                ew.eq("owner_id", condition.get("ownerId").toString());
            }
            if (condition.containsKey("materielId") && Objects.nonNull(condition.get("materielId"))) {
                ew.eq("materiel_id", condition.get("materielId").toString());
            }
            if (condition.containsKey("storeHouseId") && Objects.nonNull(condition.get("storeHouseId"))) {
                ew.eq("store_house_id", condition.get("storeHouseId").toString());
            }
            if (!Objects.isNull(condition.get("locationCode")) && StringUtils.isNotBlank(condition.get("locationCode").toString().trim())) {
                ew.eq("location_code", condition.get("locationCode").toString());
            }
            if (Objects.nonNull(condition.get("startDate")) && StringUtils.isNotEmpty((String) condition.get("startDate"))) {
                ew.ge("gmt_modified", condition.get("startDate").toString());
            }
            if (Objects.nonNull(condition.get("endDate")) && StringUtils.isNotEmpty((String) condition.get("endDate"))) {
                ew.le("gmt_modified", condition.get("endDate").toString());
            }

            if (condition.containsKey("lotNo1") && Objects.nonNull(condition.get("lotNo1")) && StringUtils.isNotEmpty((String) condition.get("lotNo1"))) {
                List<String> vins = Arrays.asList(CommonMethod.setVins((String) condition.get("lotNo1")));
                ew.andNew().in("lot_no1", vins).or().like("lot_no1", condition.get("lotNo1").toString());
            }
        }
        ew.groupBy("stock_id");
        ew.orderBy("stock_id", false);
        return ew;
    }

    /**
     * 查询可用库存列表信息
     */
    @Override
    public List<StockSkuToPrepareDTO> selectStockToPrepareByParams (OutboundNoticeLine v, Long storeHouseId) {
        StockSkuToPrepareParamDTO paramDTO = new StockSkuToPrepareParamDTO();
        BeanUtils.copyProperties(v, paramDTO);
        paramDTO.setStoreHouseId(storeHouseId);
        return this.baseMapper.selectStockToPrepareByParams(paramDTO);
    }

    @Override
    public void lockStockBatch (Map<String, Object> params) {
        List<String> stockIds = (List<String>) params.get("stockIds");
        if (CollectionUtils.isEmpty(stockIds)) {
            throw new BaseException("锁定的id为空，请重新确认！");
        }
        String reason = (String) params.get("reason");
        if (StringUtils.isEmpty(reason)) {
            throw new BaseException("请输入锁定的原因！");
        }

        List<String> msgs = new ArrayList<>();
        for (String stockId : stockIds) {
            String msg = "";
            Stock stock = this.selectById(Long.valueOf(stockId));
            if ("20".equals(stock.getStatus())) {
                msg = "库存:" + stock.getId() + ":已被锁定";
                msgs.add(msg);
                continue;
            }
            baseMapper.updateStockStatus(Long.valueOf(stockId), TableStatusEnum.STATUS_20.getCode(), reason, "lock");
        }
    }

    @Override
    public void unlockStockBatch (Map<String, Object> params) {
        List<String> stockIds = (List<String>) params.get("stockIds");
        if (CollectionUtils.isEmpty(stockIds)) {
            throw new BaseException("锁定的id为空，请重新确认！");
        }
        String reason = (String) params.get("reason");
        if (StringUtils.isEmpty(reason)) {
            throw new BaseException("请输入锁定的原因！");
        }

        List<String> msgs = new ArrayList<>();
        for (String stockId : stockIds) {
            String msg = "";
            Stock stock = this.selectById(Long.valueOf(stockId));
            if ("10".equals(stock.getStatus())) {
                msg = "库存:" + stock.getId() + ":已为正常";
                msgs.add(msg);
                continue;
            }
            baseMapper.updateStockStatus(Long.valueOf(stockId), TableStatusEnum.STATUS_10.getCode(), reason, "unlock");
        }
    }

    /**
     * 更新库位
     */
    @Override
    public void updateStockLocation (Map<String, String> condition) {
        if (Objects.isNull(condition) || condition.isEmpty()) {
            throw new BaseException("参数不能为空");
        }
        User loginUser = userService.getLoginUser();
        if (Objects.isNull(loginUser)) {
            throw new BaseException("请登陆后进行该操作");
        }
        String stockId = condition.get("stockId");
        String houseId = condition.get("houseId");
        String newLocationId = condition.get("newLocationId");
        if (StringUtils.isBlank(stockId)) {
            throw new BaseException("请选择要调整库位的数据");
        }
        if (StringUtils.isBlank(houseId)) {
            throw new BaseException("仓库信息不能为空");
        }
        if (StringUtils.isBlank(newLocationId)) {
            throw new BaseException("请选择调整的库位");
        }
        HashMap<String, Object> params = Maps.newHashMap();
        params.put("stockId", stockId);
        params.put("houseId", houseId);
        List<StockWithSkuDTO> list = selectStockWithSkuByParam(params);
        if (CollectionUtils.isEmpty(list)) {
            throw new BaseException("未查询到对应stockId:" + stockId + "的库存信息");
        }
        if (list.size() > 1) {
            throw new BaseException("查询到stockId:" + stockId + "的多条库存");
        }

        StockWithSkuDTO stockDTO = list.get(0);

        //调整入库记录库位信息
        EntityWrapper<InboundPutawayLine> ew = new EntityWrapper<>();
        ew.eq("lot_no1", stockDTO.getLotNo1());
        ew.eq("materiel_id", stockDTO.getMaterielId());
        ew.eq("owner_id", stockDTO.getOwnerId());
        ew.orderBy("gmt_create", false);
        ew.orderBy("id", false);
        List<InboundPutawayLine> lineList = putawayLineService.selectList(ew);
        HashMap<String, String> propCache = Maps.newHashMap();
        Long putwayLineId = null;
        if (CollectionUtils.isEmpty(lineList)) {
            //车辆入库是通过期初库存导入
            EntityWrapper<StockInitLine> initEw = new EntityWrapper<>();
            ew.eq("lot_no1", stockDTO.getLotNo1());
            ew.eq("materiel_id", stockDTO.getMaterielId());
            ew.eq("owner_id", stockDTO.getOwnerId());
            ew.orderBy("gmt_create", false);
            ew.orderBy("id", false);
            List<StockInitLine> stockInitLines = initLineService.selectList(initEw);
            if (CollectionUtils.isEmpty(stockInitLines)) {
                throw new BaseException("未查询到车架号:" + stockDTO.getLotNo1() + "入库/期初库存信息");
            }
            StockInitLine initLine = stockInitLines.get(0);
            propCache.put("materielName", initLine.getMaterielName());
            propCache.put("relationId", String.valueOf(initLine.getId()));
        } else {
            InboundPutawayLine putawayLine = lineList.get(0);
            propCache.put("materielName", putawayLine.getMaterielName());
            propCache.put("relationId", String.valueOf(putawayLine.getId()));
            putwayLineId = putawayLine.getId();
        }
        MovementHeader mh = buildMovement(loginUser, houseId, newLocationId, stockDTO, propCache);
        boolean isUpdate = movementHeaderService.createAndAuditMovenment(mh);
        if (!isUpdate) {
            throw new BaseException("库位调整失败");
        }
        if (null != putwayLineId) {
            InboundPutawayLine inboundPutawayLine = new InboundPutawayLine();
            inboundPutawayLine.setId(putwayLineId);
            inboundPutawayLine.setUpdateLocationId(Long.valueOf(newLocationId));
            inboundPutawayLine.setUpdateLocationNo(storeLocationService.selectById(newLocationId).getName());
            putawayLineService.updateById(inboundPutawayLine);
        }
    }

    private MovementHeader buildMovement (User loginUser, String houseId, String newLocationId, StockWithSkuDTO stockDTO, HashMap<String, String> propCache) {
        MovementHeader mh = new MovementHeader();
        mh.setId(snowFlakeId.nextId());
        mh.setMovementNo(numberService.getMovementNo());
        mh.setStoreHouseId(Long.valueOf(houseId));
        mh.setOwnerId(stockDTO.getOwnerId());
        mh.setOrderDate(new Date());
        mh.setBusinessType(TableStatusEnum.STATUS_30.getCode());
        mh.setBusinessDocId(0L);
        mh.setLineCount(0);
        mh.setStatus(TableStatusEnum.STATUS_10.getCode());
        mh.setUserCreate(loginUser.getName());
        mh.setUserModified(loginUser.getName());
        mh.setGmtCreate(null);
        mh.setGmtModified(null);

        MovementLine ml = new MovementLine();
        ml.setId(snowFlakeId.nextId());
        ml.setHeaderId(mh.getId());
        ml.setType(TableStatusEnum.STATUS_30.getCode());
        ml.setOwnerId(stockDTO.getOwnerId());
        ml.setMaterielId(stockDTO.getMaterielId());
        ml.setRelationLineId(propCache.get("relationId") == null ? null : Long.valueOf(propCache.get("relationId")));
        ml.setMaterielName(StringUtils.isBlank(propCache.get("materielName")) ? null : propCache.get("materielName"));
        ml.setSourceLocationId(stockDTO.getLocationId());
        ml.setDestinationLocationId(Long.valueOf(newLocationId));
        ml.setUom(stockDTO.getUom());
        ml.setQty(stockDTO.getQty());
        ml.setNetWeight(stockDTO.getNetWeight());
        ml.setGrossWeight(stockDTO.getGrossWeight());
        ml.setGrossCubage(stockDTO.getGrossCubage());
        ml.setPackedCount(stockDTO.getPackedCount());
        ml.setLotNo0(stockDTO.getLotNo0());
        ml.setLotNo1(stockDTO.getLotNo1());
        ml.setLotNo2(stockDTO.getLotNo2());
        ml.setLotNo3(stockDTO.getLotNo3());
        ml.setLotNo4(stockDTO.getLotNo4());
        ml.setLotNo5(stockDTO.getLotNo5());
        ml.setLotNo6(stockDTO.getLotNo6());
        ml.setLotNo7(stockDTO.getLotNo7());
        ml.setLotNo8(stockDTO.getLotNo8());
        ml.setLotNo9(stockDTO.getLotNo9());
        ml.setRemarks("库存页面库位调整");
        ml.setGmtCreate(null);
        ml.setGmtModified(null);
        ArrayList<MovementLine> mls = Lists.newArrayList();
        mls.add(ml);
        mh.setMovementLineList(mls);
        return mh;
    }

    @Override
    public List<StockWithSkuDTO> selectStockWithSkuByParam (HashMap<String, Object> params) {
        return this.baseMapper.selectStockWithSkuByParam(params);
    }

    /**
     * 插入明细账
     */
    public Stock updateStockQty (StockProperty stockProperty, String type, String businessType, Long relationLineId) {
        LOGGER.info("插入库存明细车架号为 {}", stockProperty.getLotNo1());
        //库存
        Stock stock = getUniqueStock(stockProperty);
        stockProperty.setStockId(stock.getId());
        //库存明细账
        StockDetail stockDetail = new StockDetail();
        stockDetail.setId(snowFlakeId.nextId());
        stockDetail.setStockId(stockProperty.getStockId());
        stockDetail.setType(type);
        stockDetail.setBusinessType(businessType);
        stockDetail.setRelationLineId(relationLineId);
        stockDetail.setQty(stockProperty.getQty());
        stockDetail.setNetWeight(stockProperty.getNetWeight());
        stockDetail.setGrossWeight(stockProperty.getGrossWeight());
        stockDetail.setGrossCubage(stockProperty.getGrossCubage());
        stockDetail.setPackedCount(stockProperty.getPackedCount());

        //更新合格证信息
        updateCertificationStockId(stockProperty.getLotNo1(), stock.getId());
        try {
            boolean resultDetail = stockDetailService.insert(stockDetail);
            Integer result = baseMapper.updateStockQtyById(stockProperty);

            if (!resultDetail) throw new BaseException(2020, "保存库存明细失败！");
            if (result < 1) throw new BaseException(2010, "更新库存失败");

            return selectById(stockProperty.getStockId());
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 合格证更新sotckid
     *
     * @param lotNo1 车架号
     * @param id     stockid
     */
    private void updateCertificationStockId (String lotNo1, Long id) {
        LOGGER.info("{}更新合格证信息", lotNo1);
        try {
            if (StringUtils.isNotEmpty(lotNo1) && null != id) {
                CertificationInfo param = new CertificationInfo();
                param.setVin(lotNo1);
                CertificationInfo certificationInfo = certificationInfoMapper.selectOne(param);
                if (null != certificationInfo) {
                    CertificationInfo updateParam = new CertificationInfo();
                    updateParam.setId(certificationInfo.getId());
                    updateParam.setStockId(id);
                    certificationInfoMapper.updateById(updateParam);
                }
            }
        } catch (Exception e) {
            LOGGER.error("更新合格证Stockid失败！");
        }
    }

}
